﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Microsoft.Forums.MicrosoftForumsProvider;


using Microsoft.Forums.Tests.MicrosoftForumsProvider.Stubs;
using Local = Microsoft.Forums.OfflineStore;
using Web = Microsoft.Forums.MicrosoftForumsProvider.Forums;

namespace Microsoft.Forums.Tests.MicrosoftForumsProvider
{
    /// <summary>
    /// Test the MicrosoftForumsProvider, making sure it transforms the raw results from the webservice
    /// </summary>
    [TestFixture]
    public class MicrosoftForumsProviderTest
    {
        ForumsServiceStub serviceStub;

        /// <summary>
        /// Create the stub IForumService implemenation
        /// </summary>
        [SetUp]
        public void Setup()
        {
            serviceStub = new ForumsServiceStub();
        }

        /// <summary>
        /// Test to see if GetAvailableForums will convert the list of ForumResult objects into Forum objects
        /// </summary>
        [Test]
        public void GetAvailableForumsReturnsListOfForumObjects()
        {
            var f1 = new Web.Forum();
            f1.ForumId = Guid.NewGuid();
            f1.UniqueName = "Forum";
            var f2 = new Web.Forum();
            f2.ForumId = Guid.NewGuid();
            f2.UniqueName = "Forum2";
            var f3 = new Web.Forum();
            f3.ForumId = Guid.NewGuid();
            f3.UniqueName = "Forum2";

            serviceStub.GetAllForums_Result = new List<Web.Forum> { f1, f2, f3 };
            var provider = new MicrosoftForumsServiceProvider(serviceStub);

            var results = provider.GetAvailableForums("someBrand", 1000);

            Assert.AreEqual(3, results.Count);
            Assert.AreEqual(f1.ForumId, results[0].Id);
            Assert.AreEqual(f2.ForumId, results[1].Id);
            Assert.AreEqual(f3.ForumId, results[2].Id);
        }


        /// <summary>
        /// Test to see if GetUpdatedThreads will throw an ArgumentOutOfRangeException if the fromDate is greate than the toDate
        /// </summary>
        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void GetUpdatedThreadsThrowsExceptionOnInvalidTimeRange()
        {
            var provider = new MicrosoftForumsServiceProvider(serviceStub);

            var results = provider.GetUpdatedThreads(Guid.NewGuid(), DateTime.Now, DateTime.Now.AddDays(-1));
        }


        /// <summary>
        /// Test to see if GetUpdatedThreads will convert a list ThreadResult objects into Thread objects
        /// Since we implement paging we need to send many threads to make sure the multiple calls are concatenated together
        /// Since we expect both updated and new threads we pass in both
        /// </summary>
        [Test]
        public void GetUpdatedThreadsReturnsListOfThreads()
        {
            var updatedThreads = new List<Web.BriefThread>();
            var createdThreads = new List<Web.BriefThread>();

            // Since created and updated can return common thread test this
            var commonThread = new Web.Thread
            {
                Id = Guid.NewGuid(),
                CreatedOn = DateTime.Now,
                CreatedBy = new Web.BriefUser { Id = Guid.NewGuid() },
                RootMessageId = Guid.NewGuid()
            };
            updatedThreads.Add(commonThread);
            createdThreads.Add(commonThread);

            for (int i = 0; i < 30; i++)
            {
                updatedThreads.Add(new Web.Thread
                {
                    Id = Guid.NewGuid(),
                    CreatedOn = DateTime.Now,
                    CreatedBy = new Web.BriefUser { Id = Guid.NewGuid() },
                    RootMessageId = Guid.NewGuid()
                });

                createdThreads.Add(new Web.BriefThread
                {
                    Id = Guid.NewGuid(),
                    CreatedOn = DateTime.Now,
                    CreatedBy = new Web.BriefUser { Id = Guid.NewGuid() },
                    RootMessageId = Guid.NewGuid()
                });
            }
            serviceStub.GetUpdatedThreads_Result = updatedThreads;
            serviceStub.GetCreatedThreads_Result = createdThreads;
            var provider = new MicrosoftForumsServiceProvider(serviceStub);

            var results = provider.GetUpdatedThreads(Guid.NewGuid(), DateTime.Now.AddDays(-1), DateTime.Now);

            Assert.AreEqual(updatedThreads.Count + createdThreads.Count - 1, results.Count);
            foreach (var t in updatedThreads)
            {
                Assert.IsTrue(results.Any(
                    th => th.Id == t.Id &&
                    th.CreatedOn == t.CreatedOn &&
                    th.CreatedById == t.CreatedBy.Id
                    ));
            }
            foreach (var t in createdThreads)
            {
                Assert.IsTrue(results.Any(
                    th => th.Id == t.Id &&
                    th.CreatedOn == t.CreatedOn &&
                    th.CreatedById == t.CreatedBy.Id
                    ));
            }
        }

        /// <summary>
        /// Test to see if GetAllThreads will convert a list ThreadResult objects into Thread objects
        /// Since we implement paging we need to send many threads to make sure the multiple calls are concatenated together
        /// </summary>
        [Test]
        public void GetAllThreadsReturnsListOfThreads()
        {
            var threads = new List<Web.BriefThread>();
            for (int i = 0; i < 30; i++)
            {
                threads.Add(new Web.BriefThread
                {
                    Id = Guid.NewGuid(),
                    CreatedOn = DateTime.Now,
                    RootMessageId = Guid.NewGuid(),
                    CreatedBy = new Web.BriefUser { Id = Guid.NewGuid() }
                });
            }
            serviceStub.GetForumThreads_Result = threads;
            var provider = new MicrosoftForumsServiceProvider(serviceStub);

            var results = provider.GetAllThreads(Guid.NewGuid());

            Assert.AreEqual(threads.Count, results.Count);
            foreach (var t in threads)
            {
                Assert.IsTrue(results.Any(
                    th => th.Id == t.Id &&
                    th.CreatedOn == t.CreatedOn &&
                    th.CreatedById == t.CreatedBy.Id
                    ));
            }

        }

        /// <summary>
        /// Test to see if GetUpdatedPosts will throw an ArgumentOutOfRangeException if the fromDate is greater than the toDate
        /// </summary>
        [Test]
        [ExpectedException(typeof(ArgumentOutOfRangeException))]
        public void GetUpdatedPostsThrowsExceptionOnInvalidTimeRange()
        {
            var provider = new MicrosoftForumsServiceProvider(serviceStub);

            var results = provider.GetUpdatedThreads(Guid.NewGuid(), DateTime.Now, DateTime.Now.AddDays(-1));
        }

        /// <summary>
        /// Test to see if GetUpdatedPosts will convert a list MessageResult objects into Post objects
        /// Since we implement paging we need to send many posts to make sure the multiple calls are concatenated together
        /// </summary>
        [Test]
        public void GetUpdatedPostsReturnsListOfPosts()
        {
            var messages = new List<Web.BriefMessage>();
            for (int i = 0; i < 25; i++)
            {
                messages.Add(new Web.BriefMessage
                {
                    Id = Guid.NewGuid(),
                    CreatedOn = DateTime.Now,
                    CreatedBy = new Web.User { Id = Guid.NewGuid() }
                });
            }
            serviceStub.GetNewOrModifiedMessages_Result = messages;
            var provider = new MicrosoftForumsServiceProvider(serviceStub);

            var results = provider.GetUpdatedPosts(Guid.NewGuid(), Guid.NewGuid(), DateTime.Now.AddDays(-1), DateTime.Now);

            Assert.AreEqual(messages.Count, results.Count);
            foreach (var m in messages)
            {
                Assert.IsTrue(results.Any(
                    p => p.Id == m.Id &&
                    p.CreatedOn == m.CreatedOn &&
                    p.CreatedBy.Id == m.CreatedBy.Id
                    ));
            }

        }

        /// <summary>
        /// Test to see if GetAllPosts will convert a list MessageResult objects into Post objects
        /// Since we implement paging we need to send many posts to make sure the multiple calls are concatenated together
        /// </summary>
        [Test]
        public void GetAllPostsReturnsListOfPosts()
        {
            var messages = new List<Web.BriefMessage>();
            for (int i = 0; i < 25; i++)
            {
                messages.Add(new Web.BriefMessage
                {
                    Id = Guid.NewGuid(),
                    CreatedOn = DateTime.Now,
                    CreatedBy = new Web.User { Id = Guid.NewGuid() }
                });
            }
            serviceStub.GetThreadMessages_Result = messages;
            var provider = new MicrosoftForumsServiceProvider(serviceStub);

            var results = provider.GetAllPosts(Guid.NewGuid(), Guid.NewGuid());

            Assert.AreEqual(messages.Count, results.Count);
            foreach (var m in messages)
            {
                Assert.IsTrue(results.Any(
                    p => p.Id == m.Id &&
                    p.CreatedOn == m.CreatedOn &&
                    p.CreatedBy.Id == m.CreatedBy.Id
                    ));
            }

        }
    }
}

